﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Badger.Vhdl.Types;
using Weazel.Badger.Vhdl.Statements;

#endregion

namespace Weazel.Badger.Vhdl.Expressions
{
  public class ConstantExpression : Expression
  {
    private string value;
    private TypeSet types = new TypeSet();

    public string Value
    {
      get
      {
        return value;
      }

      set
      {
        this.value = value;
      }
    }

    public int GetValue()
    {
      return new Weazel.Math.Integer(value).ToInt();
    }

    /// <summary>
    /// Create a constant expression with a specific type.
    /// </summary>
    /// <param name="value">Value of the constant</param>
    /// <param name="type">Type of the constant</param>
    public ConstantExpression(
			IComponent parentContainer,
			string value, 
			Vhdl.Types.Type type, 
			GezelType gezelType
		) 
			: base(parentContainer, type, gezelType)
    {
      this.value = value;
      this.types.Add(type);
    }

		public ConstantExpression(int integerValue)
			: this(null, integerValue.ToString(), new Integer(32), null)
		{
		}

    /// <summary>
    /// Create a constant expression of a specified type.
    /// </summary>
    /// <param name="value">Value of the constant</param>
    /// <param name="type">Type of the constant</param>
    /// <param name="parent">The parent expression or stmt container</param>
    /// <param name="expr">GEZEL reference expression</param>
    public ConstantExpression(
			IComponent parentContainer,
      string value, 
      Vhdl.Types.Type type,
      GezelType gezelType,
      Gezel.Model.Expression expr
    ) 
      : base(parentContainer, type, gezelType, expr)
    {
      this.value = value;
      this.types.Add(type);
    }

    /// <summary>
    /// Create a constant expression with multiple possible types. The type for such an 
    /// expression is initially set to "undefined". This must be resolved before writing
    /// the model in order to avoid an errornous result.
    /// </summary>
    /// <param name="value">Value of the constant</param>
    /// <param name="types">Possible types</param>
    public ConstantExpression(
			IComponent parentContainer,
			string value, 
			Vhdl.Types.Type[] types
		) 
			: base(parentContainer, new UndefinedType(), null)
    {
      this.value = value;
      this.types.AddRange(types);
    }

    public ConstantExpression(
			IComponent parentContainer,
      string value, 
      Vhdl.Types.Type[] types,
      Gezel.Model.Expression expr
    ) 
      : base(parentContainer, new UndefinedType(), null, expr)
    {
      this.value = value;
      this.types.AddRange(types);
    }

    public override bool VerifyType(ref List<VerifyMessage> messages)
    {
      if (this.Type == Types.Types.Undefined)
      {
        messages.Add(new VerifyMessage(string.Format("no type set for constant '{0}'", value)));
        return false;
      }

      verified = true;
      return true;
    }


		public override void SetActualType(Entity entity, Process process, Statements.StatementCollection statements, Vhdl.Types.Type type)
    {
      if (resolved)
      {
        if (this.Type != type)
          throw new Exception();

        return;
      }

      if (object.Equals(type, null))
        throw new NullReferenceException();

      this.Type = type;

      resolved = true;
    }

    public override TypeSet GetPossibleTypes()
    {
      return types;
    }

    public override string ToString()
    {
      if (this.Type == Types.Types.Undefined)
        return "TYPE IS NULL";
      
      if(this.Type.TypeId == Types.Types.StdLogic && value.Length == 1)
        return "'" + value + "'";
      else
        return value;

    }
  }
}
